<script minify>
App.components({ 
    PreviewObject({ val, fieldAttrs, attrs }) {
        let num = n => n
        let date = toDate
        let pad = d =>  d < 10 ? '0' + d : d
        let dmft = d => d.getFullYear() + '/' + pad(d.getMonth() + 1) + '/' + pad(d.getDate())
        let str = s => s.substring(0, 6) === '/Date(' ? dmft(date(s)) : s.trim()
        let scalarFns = {
            string: str,
            number: num,
            boolean: x => x ? 'true' : 'false',
            'null': x => '',
            'undefined': x => ''
        }
        let scalarTypes = Object.keys(scalarFns)
        return {
            $template: '#preview-object-template',
            get val() { return resolve(val) },
            fieldAttrs: fieldAttrs || (k => ({})),
            get attrs() { return resolve(attrs) },
            get isScalar() { return scalarTypes.indexOf(typeof this.val) >= 0 },
            get scalarValue() {
                let v = this.val
                let f = scalarFns[typeof v]
                return f ? f(v) : v == null ? '' : v
            },
            num,
            str,
        }
    },
    ObjectPreview({ val, fieldAttrs }) {
        let show = k => typeof k !== 'string' || k.substring(0, 2) !== '__'
        let keyFmt = t => humanize(toPascalCase(t))
        return {
            $template: '#object-preview-template',
            get val() { return resolve(val) },
            fieldAttrs: fieldAttrs || (k => ({})),
            get type() { return typeof this.val },
            get keys() { return resolve(this.val, v => !v ? [] : Object.keys(v).filter(show)) },
            get rows() { return this.keys.map(k => ({ key:keyFmt(k), val: this.val[k] })) },
        }
    },
    ArrayPreview({ val, fieldAttrs }) {
        let show = k => typeof k !== 'string' || k.substring(0, 2) !== '__'
        function isScalar(o) { return typeof o == 'string' || typeof o == 'number' || typeof o == 'boolean' }
        return {
            $template: '#array-preview-template',
            get val() { return resolve(val) },
            fieldAttrs: fieldAttrs || (k => ({})),
            get isScalar() { return isScalar(this.val && this.val[0]) },
            get uniqueKeys() { return this.isScalar || !Array.isArray(this.val) ? [] : uniqueKeys(this.val).filter(show) },
            keyFmt: t => humanize(toPascalCase(t)),
        }
    } 
})
</script>
<!--minify-->
<template id="preview-object-template">
<div v-bind="attrs" v-if="isScalar"><span>{{scalarValue}}</span></div>
<div v-bind="attrs" v-else-if="Array.isArray(val)" v-scope="ArrayPreview({ val: () => val, fieldAttrs })"></div>
<div v-bind="attrs" v-else v-scope="ObjectPreview({ val: () => val, fieldAttrs })"></div>
</template>
<template id="array-preview-template">
<span v-if="isScalar" v-html="val"></span>
<div v-else class="flex flex-col">
    <div class="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
        <div class="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8">
            <div class="md:shadow overflow-hidden border-b border-gray-200 md:rounded-lg">    
                <table class="table-array min-w-full divide-y divide-gray-200">
                    <thead class="bg-gray-50">
                    <tr>
                        <th v-for="k in uniqueKeys" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider whitespace-nowrap">
                            <b></b>{{keyFmt(k)}}
                        </th>
                    </tr>
                    </thead>
                    <tbody>
                        <tr v-for="(row,index) in val" :class="index % 2 == 0 ? 'bg-white' : 'bg-gray-50'">
                            <td v-for="k in uniqueKeys" class="px-6 py-4 whitespace-nowrap text-sm text-gray-900"
                                v-scope="PreviewObject({ val:() => row[k], fieldAttrs, attrs:() => fieldAttrs(k) })">
                            </td>
                        </tr>
                    </tbody>
                </table>
            </div>
        </div>
    </div>
</div>
</template>
<template id="object-preview-template">
<table class="table-object">
    <tr v-for="row in rows">
        <th class="text-left font-medium align-top py-2 px-4 whitespace-nowrap">{{row.key}}</th>
        <td class="align-top py-2 px-4" v-scope="PreviewObject({ val:() => row.val, fieldAttrs, attrs:() => fieldAttrs(row.key) })"></td>
    </tr>
</table>
</template>
<!--/minify-->
